package com.minisoft.utils;

import cn.hutool.http.HttpUtil;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

public class SignatureGenerator {

    private static final String ALGORITHM = "HmacSHA1";
    private static final String ENCODING = "UTF-8";
    private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";

    public static String generateSignature(String accessKeySecret, String httpMethod, String host, String path,
                                            Map<String, String> queryParams, Map<String, String> bodyParams) {
        String timestamp = getUTCTimestamp();
        String urlParam = buildUrlParam(httpMethod, host, path, queryParams, bodyParams, timestamp);
        String signature = calculateSignature(accessKeySecret, urlParam);
        return signature;
    }

    private static String buildUrlParam(String httpMethod, String host, String path, Map<String, String> queryParams,
                                         Map<String, String> bodyParams, String timestamp) {
        StringBuilder sb = new StringBuilder();
        sb.append(httpMethod.toUpperCase()).append(host).append(path).append("?");
        Map<String, String> params = new TreeMap<>();
        params.put("AccessKeyId", queryParams.get("AccessKeyId"));
        params.put("Expires", queryParams.get("Expires"));
        params.put("Timestamp", queryParams.get("Timestamp"));
        params.putAll(queryParams);
        params.putAll(bodyParams);
        List<String> paramList = new ArrayList<>();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String name = entry.getKey();
            String value = entry.getValue();
            if (value != null && !value.isEmpty()) {
                String encodedName = urlEncode(name);
                String encodedValue = urlEncode(value);
                paramList.add(encodedName + "=" + encodedValue);
            }
        }
        String paramString = String.join("&", paramList);
        sb.append(paramString);
        return sb.toString();
    }

    private static String calculateSignature(String accessKeySecret, String urlParam) {
        try {
            SecretKeySpec keySpec = new SecretKeySpec(accessKeySecret.getBytes(ENCODING), ALGORITHM);
            Mac mac = Mac.getInstance(ALGORITHM);
            mac.init(keySpec);
            byte[] signatureBytes = mac.doFinal(urlParam.getBytes(ENCODING));
            String signature = Base64.getEncoder().encodeToString(signatureBytes);
//            return urlEncode(signature);
            return signature;
        } catch (NoSuchAlgorithmException | InvalidKeyException | java.io.UnsupportedEncodingException e) {
            throw new RuntimeException("Failed to generate signature", e);
        }
    }

    private static String urlEncode(String value) {
        try {
            return URLEncoder.encode(value, ENCODING)
                    .replace("+", "%20")
                    .replace("*", "%2A")
                    .replace("%7E", "~");
        } catch (java.io.UnsupportedEncodingException e) {
            throw new RuntimeException("Failed to encode value", e);
        }
    }

    private static String getUTCTimestamp() {
        TimeZone timeZone = TimeZone.getDefault();
        Calendar calendar = Calendar.getInstance(timeZone);
        SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT);
        dateFormat.setTimeZone(timeZone);
        return dateFormat.format(calendar.getTime());
    }

    public static void main(String[] args) {
        String accessKeyId = "1438ff588427d93d10a092b896a34ea4";
        String accessKeySecret = "4w8Xo4AF25f669YB95l5";
        String httpMethod = "GET";
        String host = "clink-openapi-test.cnhuafas.com";
        String path = "/list_clients";
        Map queryParams = new HashMap<>();
        queryParams.put("AccessKeyId", accessKeyId);
        queryParams.put("Expires", "60");
        queryParams.put("Timestamp", SignatureGenerator.getUTCTimestamp());
        queryParams.put("limit", "10");
        queryParams.put("offset", "0");
        Map<String, String> bodyParams = new HashMap<>();
        String signature = SignatureGenerator.generateSignature(accessKeySecret, httpMethod, host, path, queryParams, bodyParams);
        System.out.println("Signature: " + signature);
        queryParams.put("Signature",signature);
//        doGet("https://clink-openapi-test.cnhuafas.com/list_clients");

        String s = HttpUtil.get("https://clink-openapi-test.cnhuafas.com/list_clients", queryParams);
        System.out.println(s);
    }

    private static void doGet(String urlStr){
        try {
            URL url = new URL(urlStr);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod("GET");
            int status = con.getResponseCode();
            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            String inputLine;
            StringBuffer content = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                content.append(inputLine);
            }
            in.close();
            con.disconnect();
            System.out.println(content.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
